package com.alibaba.travel.comment.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.alibaba.travel.comment.constant.GradeConstant;
import com.alibaba.travel.comment.dao.CommentDao;
import com.alibaba.travel.comment.dto.CommentDto;
import com.alibaba.travel.comment.dto.entity.CommentEntity;
import com.alibaba.travel.comment.dto.entity.UserCommentHistoryEntity;
import com.alibaba.travel.comment.feign.UserLikesRecordFeign;
import com.alibaba.travel.comment.interceptor.LoginInterceptor;
import com.alibaba.travel.comment.service.MongoService;
import com.alibaba.travel.comment.service.UserCommentHistoryService;
import com.alibaba.travel.common.model.dto.ContentEntity;
import com.alibaba.travel.common.utils.RRException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.alibaba.travel.comment.service.CommentService;
import com.alibaba.travel.common.utils.Query;
import com.alibaba.travel.common.utils.PageUtils;
import org.springframework.util.ObjectUtils;


@Service("commentService")
public class CommentServiceImpl extends ServiceImpl<CommentDao, CommentEntity> implements CommentService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private MongoService mongoService;



    @Override
    public PageUtils queryAll(Map<String, Object> params) {
        // 分页查询一级
        LambdaQueryWrapper<CommentEntity> queryWrapper = new LambdaQueryWrapper<CommentEntity>()
                .eq(CommentEntity::getGrade, GradeConstant.FIRST_GRADE);
        IPage<CommentEntity> page = this.page(
                new Query<CommentEntity>().getPage(params),
                queryWrapper
        );
        // 根据一级评论封装二级评论
        List<CommentDto> result = new ArrayList<>();
        page.getRecords().forEach(parent -> {
            long count = 0;
            CommentDto commentDto = new CommentDto();
            // 评论基本信息
            BeanUtils.copyProperties(parent, commentDto);
            // 评论内容
            ContentEntity contentEntity = mongoTemplate.findById(parent.getContentId(), ContentEntity.class);
            commentDto.setContent(contentEntity.getContent());
            // 子评论
            List<CommentDto> childrenList = findChildrenById(parent.getId());
            commentDto.setChildrenList(childrenList);
            // 设置回复数
            for (CommentDto next : childrenList) {
                count += next.getCommentNumber() + 1;
            }
            commentDto.setCommentNumber(count);
            commentDto.setLikesNumber(getLikes(parent));

            result.add(commentDto);
        });

        PageUtils pageUtils = new PageUtils(page);
        pageUtils.setList(result);
        return pageUtils;
    }

    // 查
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CommentEntity> page = this.page(
                new Query<CommentEntity>().getPage(params),
                new QueryWrapper<CommentEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * topic id用户链接前一个，便于查询
     * to id用户记录回复对象信息
     */
    private List<CommentDto> findChildrenById(Long parentId) {
        List<CommentEntity> childrenList = this.baseMapper.selectList(new LambdaQueryWrapper<CommentEntity>()
                .eq(CommentEntity::getTopicId, parentId));
        List<CommentDto> result = new ArrayList<>();
        for (CommentEntity child : childrenList) {
            long count = 0;
            CommentDto commentDto = new CommentDto();
            // 评论基本信息
            BeanUtils.copyProperties(child, commentDto);
            // 评论内容
            ContentEntity contentEntity = mongoTemplate.findById(child.getContentId(), ContentEntity.class);
            commentDto.setContent(contentEntity.getContent());
            // 子评论
            List<CommentDto> nextList = findChildrenById(child.getId());
            commentDto.setChildrenList(nextList);
            // 回复数
            for (CommentDto next : nextList) {
                count += next.getCommentNumber();
            }
            commentDto.setCommentNumber(count);
            // 点赞数
            Long likesNumber = getLikes(child);

            result.add(commentDto);
        }
        // 二级评论 - 按照时间排序
        result.sort((CommentDto a, CommentDto b) ->{
            // 大于为 1-交换，小于/登录 为-1不交换
            return a.getCreateTime().compareTo(b.getCreateTime());
        });
        return result;
    }
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserLikesRecordFeign userLikesRecordFeign;
    /**
     *查 Redis + Mysql
     * 更新数据库信息
     */
    private Long getLikes(CommentEntity comment) {
        // 1.查数据库
        long count = userLikesRecordFeign.getLikesNumber(comment.getId()).getData("count", new TypeReference<Long>(){});
        // 2.查缓存数量
        int size = redisTemplate.keys(comment.getTopicType() + ":" + comment.getId().toString() + "*").size();
        count += size;
        // 异步更新当前的点赞数
        comment.setLikesNumber(count);
        updateAsync(comment);

        return Long.valueOf(count);
    }

    @Autowired
    private ThreadPoolExecutor executor;

    private void updateAsync(CommentEntity entity) {
        CompletableFuture.runAsync(() -> {
            saveOrUpdate(entity);
        }, executor);
    }


    // TODO 保存后评论信息展示问题
    @Override
    public boolean save(CommentDto entity) {
        // 1.创建CommentEntity，保存
        CommentEntity comment = createCommentEntity(entity);
        this.baseMapper.insert(comment);
        // 2.创建ContentEntity， 保存
        ContentEntity content = createContentEntity(entity);
        mongoService.updateById(content);
        // 3.评论后添加历史记录信息
        insertHistoryRecord(entity);
        return true;
    }

    @Autowired
    private UserCommentHistoryService userCommentHistoryService;

    private Boolean insertHistoryRecord(CommentDto entity) {
        UserCommentHistoryEntity history = new UserCommentHistoryEntity();
        if (ObjectUtils.isEmpty(LoginInterceptor.userIdLocal.get())) {
            throw new RRException("用户未登录");
        }
        history.setUserId(LoginInterceptor.userIdLocal.get());
        LoginInterceptor.userIdLocal.remove();;
        history.setCommentId(entity.getId());
        // TODO 设置topicId ，topic Type用于直接跳转文章

        boolean save = userCommentHistoryService.save(history);
        return save;
    }

    private CommentEntity createCommentEntity(CommentDto entity) {
        CommentEntity comment = new CommentEntity();
        BeanUtils.copyProperties(entity, comment);
        return comment;
    }

    private ContentEntity createContentEntity(CommentDto entity) {
        ContentEntity content = new ContentEntity();
        BeanUtils.copyProperties(entity, content);
        return content;
    }

    /**
     * 对于某条一级评论而言，他的删除会导致其他评论消失
     * 对于莫条二级评论而言，他的删除需要将其子评论的 topicId挂载到 当前删除评论的topicId
     * 递归查询其所有子节点
     */
    @Override
    public void deleteByIds(List<Long> ids) {
        // 删除评论
        ids.stream().forEach(id -> {
            // 判断当前评论是否属于当前用户的
            CommentEntity parent = this.baseMapper.selectById(id);
            if (ObjectUtils.isEmpty(parent)) {
                throw new RRException("当前用户未登录，没有访问权限");
            }
            if (!parent.getFromId().equals(LoginInterceptor.userIdLocal.get())) {
                throw new RRException("非发出人不能删除当前评论");
            }
            // 1、查出所有的子节点
            // 2、判断当前节点的等级
            if (GradeConstant.FIRST_GRADE.equals(parent.getGrade())) {
                // 一级 删除所有子节点
                deleteAllChildren(parent.getId());
            } else {
                // 二级 为所有一级子节点换父节点
                changeChildrenTopicId(parent);
            }
        });
    }

    private boolean changeChildrenTopicId(CommentEntity parent) {
        List<CommentEntity> childrenList = this.baseMapper.selectList(new LambdaQueryWrapper<CommentEntity>()
                .eq(CommentEntity::getTopicId, parent.getId()));
        // 修改 topicId 为 parent.getTopicId();
        childrenList.stream().forEach(child -> {
            child.setTopicId(parent.getTopicId());
        });
        boolean b = this.updateBatchById(childrenList);
        return b;
    }

    private void deleteAllChildren(Long parentId) {
        // 1、查
        List<CommentEntity> childrenList = this.baseMapper.selectList(new LambdaQueryWrapper<CommentEntity>()
                .eq(CommentEntity::getTopicId, parentId));
        // 2、删
        childrenList.stream().forEach(child -> {
            deleteAllChildren(child.getId());
            // 删评论
            mongoService.removeById(child.getContentId());
            // 删评论信息
            int i = this.baseMapper.deleteById(child.getId());
        });
    }


}